#ifndef EXPRESSION
#define EXPRESSION

#include "Logger.hpp"

#include "Error.hpp"

#include "ExpressionValue.hpp"
#include "ExpressionCalcul.hpp"

/**
	@brief niveau d'erreur

	niveau d'erreur sur les expressions (pour les exceptions de type Error)
*/
#define EXPRESSION_LEVEL_ERROR			10

/**
	@brief code d'erreur

	code d'erreur en cas de typage incorrect dans une expression
*/
#define EXPRESSION_BAD_TYPE 			1

/**
	@brief code d'erreur

	code d'erreur en cas de valeur incorrecte dans une expression
*/
#define EXPRESSION_NUMERIC_ERROR        2

/**
	@brief code d'erreur

	code d'erreur en cas de classe incorrecte dans une expression
*/
#define EXPRESSION_BAD_CLASS 			3

/**
    @class Expression
    @brief abstraction des expressions

    classe abstraite définissant ce que doit pouvoir faire une expresion
*/
class Expression
{
    public:
  ~Expression(){}
        /**
            @brief calcul de l'expression

            méthode virtuelle pure, à implémenter dans chaque type d'expression pour expliciter le calcul de l'expression
        */
        virtual void compute () = 0;
        /**
            @brief affichage de l'expression

            méthode virtuelle pure, à implémenter dans chaque type d'expression pour expliciter l'affichage de l'expression
            @param [in] shift le décalage à appliquer en cas de saut de ligne
        */
        virtual void display ( const unsigned int shift = 0 ) const = 0;
        /**
            @brief accès à la valeur (mode const)

            renvoie la valeur de l'expression (à utiliser après avoir demandé à l'expression de se calculer)
            @return la valeur de l'expression
        */
        virtual ExpressionValue getValue () const
        {
            return _value;
        }
        /**
            @brief accès à la valeur (mode non const)

            renvoie la valeur de l'expression (à utiliser après avoir demandé à l'expression de se calculer)
            @return la valeur de l'expression
        */
        virtual ExpressionValue& getValue ()
        {
            return _value;
        }
        /**
            @brief accès au type (mode const)

            renvoie le type de l'expression (à utiliser après avoir demandé à l'expression de se calculer)
            @return le type de l'expression
        */
        virtual Type getType () const
        {
            return _value._type;
        }
    protected:
        /// valeur de l'expression
        ExpressionValue _value;
};

class Atom :
    virtual public Expression
{
    public:
  virtual ~Atom(){}
        virtual void compute () = 0;
        virtual void display ( const unsigned int shift = 0 ) const = 0;
};

#endif
